/**
 * @file    hal_rf433.c
 * @author  Azolla (1228449928@qq.com)
 * @brief   
 * @version 0.1
 * @date    2022-12-06
 * 
 * @copyright Copyright (c) 2022
 * */
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "esp_log.h"
#include <stdlib.h>
#include <string.h>
#include <sys/cdefs.h>
#include "esp_log.h"
#include "esp_attr.h"

#include "hal_gpio.h" 

// ESP32C3-RMT接收模式下，需要禁用 "SOC_RMT_SUPPORT_RX_PINGPONG", 不然会一直报错 "E rmt: received symbols truncated"  
// #include "driver/rmt_rx.h"   
// #include "driver/rmt_tx.h"   
#include "hal_rmt_rx.h"   // 这是复制rmt_rx.c重命名为：hal_rmt_rx.c 取消了SOC_RMT_SUPPORT_RX_PINGPONG功能

#include "hal_rf433.h"

#define CONFIG_RMT_RX_MEM_BLOCK    48    // >48
 
// #define TAG  "hal_rf433"

/* RF433/RF315 滤波算法：使用连续相同周期进行过滤 */
typedef struct {
#define FILTER_CYCLE_OK     8     // 连续过滤相同周期OK值
#define FILTER_CYCLE_FAIL   4     // 连续过滤相同周期FAIL值
#define FILTER_CYCLE_ERROR  200   // 过滤周期上下误差阈值    
    uint16_t cycle_curr;    // 当前周期
    uint16_t cycle_last;    // 上次周期
    uint8_t  ok_cnt;        // 周期连续相同的次数
    uint8_t  fail_cnt;      // 周期连续失败的次数
    bool     status;        // 1: 过滤成功！0：过滤失败，数据不对！
} rf_filter_t;

static QueueHandle_t xQueue = NULL;

static uint8_t rf_rmt_decode(uint8_t *data, const rmt_symbol_word_t *items, size_t length)
{
    uint8_t len = 0;
    static rf_filter_t rf = { 0 };
    if (length != 25) return 0;   // 这里正对性优化判断，使用遥控是3Bytes的！
    // if (length < 16 || length > 25) return 0;   // 长度错误！
    for (uint8_t i = 0, pos = 0; i < length; i++) {
        rf.cycle_curr = items[i].duration0 + items[i].duration1;
        // printf("%d: %d+%d=%d \r\n", i, items[i].duration0, items[i].duration1, rf.cycle_curr);
        if (rf.status == 0 && length - i <= FILTER_CYCLE_OK)  return 0;   // 剩余长度不够了！
        if (rf.cycle_curr > FILTER_CYCLE_ERROR &&
            rf.cycle_last > rf.cycle_curr - FILTER_CYCLE_ERROR &&  
            rf.cycle_last < rf.cycle_curr + FILTER_CYCLE_ERROR) { /* 通过连续相同周期进行过滤 */
            if (rf.status) {  // 过滤完成了！
                if (items[i].duration0 > items[i].duration1) {  // level0: 是高电平
                    data[len] |= 1 << (7 - pos);  // 高位先发
                }
                if (++pos >= 8) {  // 1Byte = 8Bit
                    pos = 0;
                    len++;
                }
            } else if (++rf.ok_cnt > FILTER_CYCLE_OK) {  
                rf.ok_cnt = 0;
                rf.status = 1;  // 过滤成功
                return 0;
            } 
            rf.fail_cnt = 0;
        } else {  // error
            rf.ok_cnt = 0;
            if (++rf.fail_cnt > FILTER_CYCLE_FAIL) {
                rf.cycle_last = rf.cycle_curr;
                rf.fail_cnt = 0;
                rf.status = 0;  // 过滤失败
            } 
        }
    }
    return len;
}
 
static rf_cb_func_t rf_callback_func = NULL; 

// RF接收消息服务回调函数
static void rf_register_callback(rf_cb_func_t cb_func)
{
    rf_callback_func = cb_func;
}
 
static bool IRAM_ATTR rmt_rx_done_callback(rmt_channel_handle_t channel, const rmt_rx_done_event_data_t *edata, void *user_data)
{
    BaseType_t high_task_wakeup = pdFALSE;
    QueueHandle_t xQueue = (QueueHandle_t)user_data;
    // send the received RMT symbols to the parser task
    xQueueSendFromISR(xQueue, edata, &high_task_wakeup);
    return high_task_wakeup == pdTRUE;
}

static void rmt_rx_task(void *arg)
{
    rmt_channel_handle_t rx_channel = (rmt_channel_handle_t)arg;
    // save the received RMT symbols
    rmt_symbol_word_t raw_symbols[CONFIG_RMT_RX_MEM_BLOCK]; // 64 symbols should be sufficient for a standard NEC frame
    rmt_rx_done_event_data_t rx_data;
    // the following timing requirement is based on RF433 protocol
    rmt_receive_config_t receive_config = {
        .signal_range_min_ns = 3000,    // the shortest duration for RF433 signal is 3us, valid signal won't be treated as noise
        .signal_range_max_ns = 9000000, // the longest duration for RF433 signal is 4000us, the receive won't stop early
    };

    while (1) {
        // ready to receive
        ESP_ERROR_CHECK(rmt_receive(rx_channel, raw_symbols, sizeof(raw_symbols), &receive_config));
        // wait for RX done signal
        if (xQueueReceive(xQueue, &rx_data, portMAX_DELAY) == pdPASS) { // pdMS_TO_TICKS(1000)
            // parse the receive symbols and print the result
            // ESP_LOGI(TAG, "num_symbols = %d", rx_data.num_symbols);
            uint8_t data[4] = { 0 };
            uint8_t len = rf_rmt_decode(data, rx_data.received_symbols, rx_data.num_symbols);
            if (len > 1) {
                // printf("rf_decode = %02x %02x %02x\n", data[0], data[1], data[2]);
                rf_callback_func(data, len);
            } else {
                // vTaskDelay(100);
            }  
        }
    }
}



void hal_rf433_init(rf_cb_func_t cb_func)
{
    rmt_rx_channel_config_t rx_channel_cfg = {
        .clk_src = RMT_CLK_SRC_DEFAULT,   // select source clock
        .resolution_hz = 1000000,         // 1MHz tick resolution, i.e. 1 tick = 1us
        .mem_block_symbols = CONFIG_RMT_RX_MEM_BLOCK,   // memory block size, 64 * 4 = 256Bytes
        .gpio_num = CONFIG_GPIO_RF433,    // GPIO number
        .flags.invert_in = false,         // don't invert input signal
        .flags.with_dma = false,          // don't need DMA backend
    };
    rmt_channel_handle_t rx_channel = NULL;
    ESP_ERROR_CHECK(rmt_new_rx_channel(&rx_channel_cfg, &rx_channel));
 
    xQueue = xQueueCreate(1, sizeof(rmt_rx_done_event_data_t));
    rmt_rx_event_callbacks_t cbs = {
        .on_recv_done = rmt_rx_done_callback,
    };
    ESP_ERROR_CHECK(rmt_rx_register_event_callbacks(rx_channel, &cbs, xQueue));

    ESP_ERROR_CHECK(rmt_enable(rx_channel));

    gpio_pullup_dis(CONFIG_GPIO_RF433);   // 不要上拉

    rf_register_callback(cb_func);
    xTaskCreatePinnedToCore(rmt_rx_task, "rmt_rx_task", 3 * 1024, rx_channel, 8, NULL, APP_CONFIG_TASK_CORE);     
}